# TurboWiki is a simple wiki module for TurboGears
#
# Copyright (C) 2009 Alberto Granzotto <agranzot@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

'''The module contains the wiki main controller.

The controller permits to view or edit a wiki page, the creation of a new page
is assigned to the edit method.

The data returned (but not all) are packed into a dict called wiki_values.
wiki_values contains the keys:
   * wiki_name: the name of the page;
   * wiki_revision: the revision number;
   * wiki_created: the date of creation for the revision;
   * wiki_user: the user who modified the content;
   * wiki_title: the title of the page;
   * wiki_content: the HTMLized content;

if you are in edit mode, you have also:
   * wiki_edit_form: the form widget for editing the page;
   * wiki_edit_submit: the value for the submit button
   * wiki_edit_action: the target action to save the changes;
   * wiki_edit_values: the values to edit;

elif you are in history mode, you have also:
   * wiki_history: the list of contents for the page, ordered by date and rev.
'''

import turbogears as tg
from turbogears import controllers, expose, flash, url, identity,\
                       redirect, validate, validators,\
                       error_handler, exception_handler
from turbogears.database import session
from cherrypy import request, response

from utils import *
from model import *
from forms import *
from widgets import *
from identity import *

__all__ = ['WikiController']

error_template = tg.config.get(
    'turbowiki.templates.error',
    'genshi:turbowiki.templates.error')
wiki_template = tg.config.get(
    'turbowiki.templates.wiki',
    'genshi:turbowiki.templates.wiki')

class WikiController(controllers.Controller):
    @expose(error_template)
    def error(self, tg_errors=None, tg_exceptions=None):
        return dict(error=tg_errors, exceptions=tg_exceptions)

    @expose()
    def index(self):
        raise redirect('view/index')

    @expose(wiki_template)
    @exception_handler(error)
    @error_handler(error)
    @validate(validators={'name': wiki_validator})
    @identity.require(can_view_wiki('name'))
    def view(self, name, rev=None):
        '''Retrieve the page data from the model, if the page does
        not exist, the method redirects to the edit view.

        Params:
        name -- the name of the page
        rev -- the revision (default None)

        Return:
        wiki_widget -- the widget to display data
        wiki_title -- the title of the page
        wiki_values -- see the description of the module
        '''
        page = Page.by_name(name)
        if not page:
            raise redirect('%s/edit/%s' % (wiki_base_url, name))
        content = page.get_content(rev=rev)
        values = dict(
            wiki_name=page.name,
            wiki_revision=content.rev,
            wiki_created=content.pretty_created,
            wiki_user=content.user,
            wiki_title=content.title,
            wiki_content=wiki_parser(content.text))
        return dict(wiki_widget=article_widget,
                wiki_title=content.title,
                wiki_values=values)

    @expose(wiki_template)
    @error_handler(error)
    @validate(validators={'name': wiki_validator})
    @identity.require(identity.All(
        can_view_wiki('name'), can_edit_wiki('name')))
    def edit(self, name, **kw):
        '''Prepare the form for editing.
        
        Params:
        name -- the name of the page
        kw -- the dict with the form values

        Return:
        wiki_widget -- the widget to display data
        wiki_title -- the title of the page
        wiki_values -- see the description of the module
        '''
        page = Page.by_name(name)
        edit_values = {'name': name}
        values = {}
        if page:
            content = page.content
            edit_values['title'] = content.title
            edit_values['lang'] = content.lang
            edit_values['text'] = content.text
            values.update(dict(
                wiki_revision=content.rev,
                wiki_created=content.pretty_created,
                wiki_user=content.user))
        if 'text' in kw:
            text_preview = wiki_parser(kw['text'])
        else:
            text_preview = ''
        values.update(dict(
                wiki_title=_('Editing %s')%name,
                wiki_name=name,
                wiki_content=text_preview,
                wiki_edit_form=wiki_form,
                wiki_edit_submit=_('save'),
                wiki_edit_action='../do_edit/%s'%name,
                wiki_edit_values=edit_values))
        return dict(wiki_widget=article_widget,
                wiki_title=values['wiki_title'],
                wiki_values=values)

    @expose()
    @error_handler(edit)
    @validate(form=wiki_form)
    @identity.require(can_edit_wiki('name'))
    def do_edit(self, name, **kw):
        '''Store the values to the model, then redirects to
        the page view.

        Params:
        name -- the name of the page
        kw -- the dict with the form values
        '''
        if kw['preview']:
            return self.edit(name, **kw)
        elif kw['back']:
            raise redirect('%s/view/%s' % (wiki_base_url, name))
        page = Page.by_name(name)

        # if the page is new we need to create it
        if not page:
            page = Page(name = name)

        msg = _('You have created of %s')
        last_rev = 0

        content = page.get_content(kw['lang'])
        # if the content of the selected language exists
        # the revision of the new content will be the value
        # of the last revision plus one.
        if content:
            msg = _('You have created a new revision of %s')
            last_rev = content.rev

        content = Content(
            #FIXME: i18n
            lang='en',
            #lang=kw['lang'],
            title=kw['title'],
            text=kw['text'],
            rev=last_rev + 1,
            user_id=get_user_id(),
            ip_address=get_user_ip()
        )
        page.contents.append(content)
        session.save(content)
        session.flush()
        flash(msg % (page.name))
        raise redirect('%s/view/%s' % (wiki_base_url, name))

    @expose(wiki_template)
    @exception_handler(error)
    @error_handler(error)
    @validate(validators={'name': wiki_validator})
    @identity.require(can_view_wiki('name'))
    def history(self, name):
        '''Retrieve the history from the model and visualise it.

        Params:
        name -- the name of the wiki page

        Return:
        wiki_widget -- the widget to display data
        wiki_title -- the title of the page
        wiki_values -- see the description of the module
        '''
        page = Page.by_name(name)
        if not page:
            raise redirect('%s/edit/%s' % (wiki_base_url, name))
        content = page.content
        values = dict(
            wiki_name=page.name,
            wiki_revision=content.rev,
            wiki_created=content.pretty_created,
            wiki_user=content.user,
            wiki_title=content.title,
            wiki_history=page.history)
        return dict(wiki_widget=history_widget,
                wiki_title=content.title,
                wiki_values=values)

